/* Copyright (c) 2007 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is confidential property of 
 * Nordic Semiconductor. The use, copying, transfer or disclosure 
 * of such information is prohibited except by express written
 * agreement with Nordic Semiconductor.
 */

 /** @file
 * Wireless Desktop USB dongle application for nRF24LU1.
 *
 * @author Lasse Olsen
 *
 */
 
#include <reg24lu1.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <intrins.h>

#include "debug.h"

#include "hal_nrf.h"
#include "hal_flash.h"
#include "hal_uart.h"

#include "timer.h"
#include "cklf.h"
#include "cpu.h"
#include "usb_api.h"
#include "lu1_bfb.h"
#include "wdp_host.h"
#include "app_param.h"

#include "mousepad.h"
#include "keyboard.h"


#include "HIDDKeyboardDriver.h"

extern volatile uint16_t timer_cnt;

typedef enum
{
  APP_PAIRING,
  APP_NORMAL,
  APP_SUSP_WE,
  APP_SUSP_WD,
  APP_TEST
} app_states_t;

//State function prototypes
app_states_t app_pairing(void);
app_states_t app_normal(void);
app_states_t app_susp_we(void);
app_states_t app_susp_wd(void);

static uint8_t radio_data[WDP_MAX_PL_LENGTH]; // General data buffer


#if 1
char putchar(char c)
{
	
 	if (c == '\n')
  	{
    	hal_uart_putchar(0x0d);                       			//output CR
  	}
	hal_uart_putchar(c);
	return c;
}


//
// _getkey, Get a char from UART.
//
char													//Return: Return char value from UART 
_getkey(void)  								
{	
	char	c;

/*	c = 0;
	if (RI)
	{
		c = SBUF;
		RI = 0;
	}
	return c;
//*/
	c = hal_uart_getchar();
	return c;
}

#endif

static void delay_ms(uint8_t ms)
{
  uint16_t i, j;																    
  
  for(i = 0; i < ms; i++ )
  {
	  for( j = 0; j < 1403; j++) // 196
	  {
		  _nop_();
	  }
  }
}

void main(void)
{
  app_states_t app_state = APP_PAIRING;
 
  CLKCTL = 0;                                 // Reset clock control register

  

#if USE_WDP				//add by hwt 

  // Set up GPIO                          
  P0DIR = 0x38;                               // Output: P0.0 - P0.2, Input: P0.3 - P0.5
  P0ALT = 0;                                  // All general I/O
  P0 = 0;                                


  // Radio + SPI setup 
  CE_LOW();                                   // Radio chip enable low
  RFCTL = 0x10;                               // Internal MCU to radio SPI enable 
  RFCKEN = 1;                                 // Radio clk enable
  RF = 1;                                     // Radio IRQ enable
  
  t2_init(FAP_RX_PERIOD);                     // Setup timer 2 used by the WDP and FAP module
  
  usb_init();                                 // Initialize USB

  wdp_host_init();                            // Initialize the Wireless Desktop Protocol (WDP)
#else
	
  // Set up GPIO							
  P0DIR = 0x38;								// Output: P0.4 , Input: P0.0- P0.3
  P0ALT = 0;									// All general I/O
  P0 = 0; 			
	hal_uart_init(UART_BAUD_57K6);

  
  usb_init();                                 // Initialize USB
  

#endif  //end if USE_WDP

  EA=1;                                       // Enable global IRQ

  
  DBG(("Wait until USB \n"));
  usb_wait_for_configuration();               // Wait until USB enumerated
  
  DBG(("Done\n"));


#if USE_WDP
  if(hal_flash_byte_read(PARAM_PREV_PAIRED) == APP_PAIRING_COMMITED)          // If dongle has paired to devices before
  {
    hal_flash_bytes_read(PARAM_MASTER_ADR0, radio_data, FAP_ADDRESS_WIDTH-1); // Read pairing earlier distributed pairing address from flash 
    wdp_host_set_master_adr(radio_data);                                      // Setup WDP using earlier used master address
  }
  else
  {
    if(hal_flash_byte_read(PARAM_PREV_PAIRED) != 0xff)                        // If flash not erased
    {                                                                         // Erase parameter page
      hal_flash_page_erase(PARAM_PAGE_N0);
    }
    wdp_host_enable_random_adr_gen();                                         // Start random address generation if no previous pairing has been committed
  } 

  timer_cnt = 0;                                                              // Reset global timing variable

  wdp_host_rx_setup(WDP_RX_PAIRING);                                          // By default listen for pairing requests on power up
  app_state = APP_PAIRING;

#else
  app_state = APP_TEST;

  HIDDKeyboardDriver_Initialize();
  memset(keyStatus, 1, NUM_KEYS);

#endif  //end if USE_WDP
  
  while(true)
  {
    switch(app_state)                                                         // State control
    {
      case APP_PAIRING:
        app_state = app_pairing();                                            // Pairing state
        break;
      case APP_NORMAL:                                                        // Normal state
        app_state = app_normal();
        break;
      case APP_SUSP_WE:                                                       // PC suspend state, remote wakeup enabled
        app_state = app_susp_we();
        break;
      case APP_SUSP_WD:                                                       // PC suspend state, remote wakeup disabled
        app_state = app_susp_wd();
        break;

      case APP_TEST:

      #if 0
		  if(JoyState() != 0) {
		  	  Joystick_Send(JoyState());
			  LED2_TOGGLE();
			  delay_ms(8);
		  }
	  #else
		
		keyboard_handle();
		delay_ms(200);
		

	  #endif
      	break;
      default:
        break;
    }
  } // End while
} // End main


app_states_t app_pairing(void)
{
  if(usb_get_state() == USB_REM_WU_ENABLE)
  {            
    return APP_SUSP_WE; 
  }          
            
  if(usb_get_state() == USB_REM_WU_DISABLE)
  {       
    return APP_SUSP_WD;                  
  }     

  wdp_host_process_events();             
  
  if(wdp_host_get_clear_pairing_result())                                 // If pairing requests received from a device 
  {
    if(hal_flash_byte_read(PARAM_PREV_PAIRED) != APP_PAIRING_COMMITED)    // If this was the very first pairing request ever 
    {
      wdp_host_get_master_adr(radio_data);
      hal_flash_bytes_write(PARAM_MASTER_ADR0, radio_data, FAP_ADDRESS_WIDTH-1);
      hal_flash_byte_write(PARAM_PREV_PAIRED, APP_PAIRING_COMMITED);      // Write master address to flash
    }  
      
    wdp_host_rx_setup(WDP_RX_NORMAL);                                  
    return APP_NORMAL;   
  }

  if(timer_cnt == APP_PAIRING_TIMEOUT)
  {
    timer_cnt = 0xffff;                                                   
    wdp_host_rx_setup(WDP_RX_NORMAL);                                  
    return APP_NORMAL;
  }  
  
  return APP_PAIRING;
}

app_states_t app_normal(void)
{
//  uint8_t dev_type, length, index;
//  uint8_t previous_app_attribute;                    
 
  if(usb_get_state() == USB_REM_WU_ENABLE)
  {
    return APP_SUSP_WE; 
  }
    
  if(usb_get_state() == USB_REM_WU_DISABLE)
  {
    return APP_SUSP_WD; 
  }

#if USE_WDP
  wdp_host_process_events();

  if(wdp_host_get_rx_data(radio_data, &length, &dev_type))                 // If radio activity
  {
    if(radio_data[APP_CMD] == APP_USER_INPUT && radio_data[APP_ATTRIBUTE] != previous_app_attribute)
    {
      previous_app_attribute = radio_data[APP_ATTRIBUTE];

      switch(dev_type)
      {
        case WDP_MOUSE:                       // If mouse data  
          if(length == APP_MOUSE_PL_LENGTH)
          {
            usb_send_packet
            (
              &radio_data[APP_DATA],
              USB_EP_MOUSE,             
              (APP_MOUSE_PL_LENGTH - APP_DATA)
            );
          }
          break;
        case WDP_KEYBOARD:                    // If keyboard data
          if(length == APP_KEYBOARD_PL_LENGTH)
          {              
            usb_send_packet
            (
              &radio_data[APP_DATA],
              USB_EP_KEYBOARD,
              (APP_KEYBOARD_PL_LENGTH - APP_DATA)
            );
          }
          break;   
      }
    } 
    else if( radio_data[APP_CMD] == APP_GET_REQUEST) // If data request received
    {        
      wdp_host_write_downlink_data(dev_type, radio_data, WDP_MAX_DL_PL_LENGTH); // Preload uplink data to device     
    }
                            
    if(!wdp_host_get_connection_status(WDP_MOUSE))     
    {
      for(index = APP_DATA; index < APP_MOUSE_PL_LENGTH; index++)
      {
        radio_data[index] = 0;
      }
      usb_send_packet(
        &radio_data[APP_DATA],
        USB_EP_MOUSE,
        (APP_MOUSE_PL_LENGTH - APP_DATA) 
      );
    }
      
    if(!wdp_host_get_connection_status(WDP_KEYBOARD))     
    {
      for(index = APP_DATA; index < APP_KEYBOARD_PL_LENGTH; index++)
      {
        radio_data[index] = 0;
      }
      usb_send_packet(
        &radio_data[APP_DATA],
        USB_EP_KEYBOARD,
        (APP_KEYBOARD_PL_LENGTH - APP_DATA)
      );
    }
  } 

#endif //end if USE_WDP

  return APP_NORMAL;
}

app_states_t app_susp_we(void)
{
  wdp_host_rx_setup(WDP_RX_SUSPEND);          // Set up WDP low power receive mode

  while (wdp_get_mode() != WDP_IDLE)          // Wait until "receive burst" finished
  ;

  if(wdp_host_process_events())               // If any radio data received during "receive burst"
  {
    wdp_host_rx_setup(WDP_RX_NORMAL);         // Wakeup PC if radio data received
    usb_wakeup();
    return APP_NORMAL;
  }
   
  // Minimize the powerconsumption by powering down the MCU 
  cklf_gpio_wakeup(0x0000, 0x0000);           // GPIO wakeup off
  cklf_rtc_disable();
  cklf_rtc_init(0x00, 0x1FFF);                // Setup power down timeout to app. 1 s
  cpu_pwr_down();                             // MCU goto sleep
       
  WUF = 0;                                    // Clear WU flag

  return APP_SUSP_WE;   
}

app_states_t app_susp_wd(void)
{
  wdp_host_rx_setup(WDP_RX_OFF);              // Disable radio to minimize power consumption
  cpu_pwr_down();                             // MCU goto sleep. May only be awaken from USB.
  wdp_host_rx_setup(WDP_RX_NORMAL);           // Setup WDP to normal receive mode
  
  return APP_NORMAL;
}
